import tkinter as tk
from PIL import Image, ImageDraw
import json

def canvas_to_image(canvas, filename):
    """
    Save the content of a tkinter.Canvas to a PNG file.
    """
    # Get the canvas width and height
    canvas_width = canvas.winfo_width()
    canvas_height = canvas.winfo_height()

    # Create an empty PIL Image
    image = Image.new("RGB", (canvas_width, canvas_height), "white")
    draw = ImageDraw.Draw(image)

    # Get all the lines and shapes from the canvas
    for item in canvas.find_all():
        coords = canvas.coords(item)
        if len(coords) == 4:  # Line segments (x1, y1, x2, y2)
            x1, y1, x2, y2 = coords
            draw.line((x1, y1, x2, y2), fill="black", width=1)

    # Save the image
    image.save(filename)
    print(f"Canvas saved as {filename}")

def generate_config_file(min_lon, max_lon, min_lat, max_lat, canvas_size, export_filename):
    # Calculate bounding box dimensions
    lon_range = max_lon - min_lon
    lat_range = max_lat - min_lat

    # Use the smaller scale for uniform scaling
    pixel_per_unit = canvas_size / max(lon_range, lat_range)
    gps_per_pixel = 1 / pixel_per_unit

    # Define the JSON structure
    config = {
        "large_rectangle": {
            "top_left": {
                "longitude": min_lon,
                "latitude": max_lat  # Top-left is the maximum latitude
            },
            "pixel_per_unit": pixel_per_unit,
            "gps_per_pixel": gps_per_pixel
        },
        "image_size": [canvas_size, canvas_size]
    }

    # Save to a JSON file
    with open(export_filename, 'w') as json_file:
        json.dump(config, json_file, indent=4)

    print(f"Configuration file saved to {export_filename}")



def read_gps_lines(filename):
    lines = []
    current_group = []

    with open(filename, 'r') as file:
        for line in file:
            stripped_line = line.strip()
            if not stripped_line:  # If it's an empty line, end the current group
                if current_group:
                    lines.append(current_group)
                    current_group = []  # Start a new group
            else:
                # Parse coordinates in the format: lon1, lat1, lon2, lat2
                coords = list(map(float, stripped_line.split(',')))
                start_point = (coords[0], coords[1])  # (lon1, lat1)
                end_point = (coords[2], coords[3])    # (lon2, lat2)
                current_group.append((start_point, end_point))

        # Add the last group if exists
        if current_group:
            lines.append(current_group)

    return lines

def scale_to_canvas(lon, lat, min_lon, max_lon, min_lat, max_lat, canvas_size, scale, offset_x, offset_y):
    lon_range = max_lon - min_lon
    lat_range = max_lat - min_lat

    # Calculate the scaling factor to ensure uniform scaling
    scale_x = canvas_size / lon_range
    scale_y = canvas_size / lat_range
    uniform_scale = min(scale_x, scale_y) * scale  # Use the smaller scale to preserve the aspect ratio

    # Apply scaling and offset to the coordinates
    x = uniform_scale * (lon - min_lon) + offset_x
    y = uniform_scale * (max_lat - lat) + offset_y  # Y-axis goes from top to bottom

    return x, y


def canvas_to_geo(x, y, min_lon, max_lon, min_lat, max_lat, canvas_size, scale, offset_x, offset_y):
    lon_range = max_lon - min_lon
    lat_range = max_lat - min_lat

    # Calculate the inverse scaling to get the geographic coordinates
    scale_x = canvas_size / lon_range
    scale_y = canvas_size / lat_range
    uniform_scale = min(scale_x, scale_y) * scale

    lon = (x - offset_x) / uniform_scale + min_lon
    lat = (max_lat - (y - offset_y) / uniform_scale)

    return lon, lat


def plot_gps_lines_tk(canvas, lines, canvas_size, scale, offset_x, offset_y):
    canvas.delete("all")
    all_points = [point for group in lines for segment in group for point in segment]
    lons, lats = zip(*all_points)
    min_lon, max_lon = min(lons), max(lons)
    min_lat, max_lat = min(lats), max(lats)

    output_lines = []  # For saving relative coordinates

    for group in lines:
        output_group = []
        for start, end in group:
            start_x, start_y = scale_to_canvas(start[0], start[1], min_lon, max_lon, min_lat, max_lat, canvas_size, scale, offset_x, offset_y)
            end_x, end_y = scale_to_canvas(end[0], end[1], min_lon, max_lon, min_lat, max_lat, canvas_size, scale, offset_x, offset_y)
            canvas.create_line(start_x, start_y, end_x, end_y, fill='black')
            output_group.append(f"{start_x},{start_y},{end_x},{end_y}")
        output_lines.append(output_group)

    # Return min/max lat/lon for use in other functions
    return min_lon, max_lon, min_lat, max_lat

def main():
    filename = r'C:\Users\17963\Desktop\ros_workspace\utm_coordinates.txt'  # Replace with your file path
    export_filename = r'C:\Users\17963\Desktop\ros_workspace\exported_lines.txt'  # Replace with export path
    json_filename = r'C:\Users\17963\Desktop\ros_workspace\config.json'  # Path for the JSON file
    png_filename = r'C:\Users\17963\Desktop\ros_workspace\canvas_output.png'  # Path for the PNG file

    gps_lines = read_gps_lines(filename)

    canvas_size = 900
    initial_scale = 1.0
    initial_offset_x = 0
    initial_offset_y = 0

    # Create Tk window
    root = tk.Tk()
    root.title("GPS Line Plotter")

    # Create Canvas
    canvas = tk.Canvas(root, width=canvas_size, height=canvas_size, bg='white')
    canvas.pack()

    # Define variables for main function scope
    scale = initial_scale
    offset_x = initial_offset_x
    offset_y = initial_offset_y

    # Get min/max lat/lon for plotting
    min_lon, max_lon, min_lat, max_lat = plot_gps_lines_tk(canvas, gps_lines, canvas_size, scale, offset_x, offset_y)

    # Generate the JSON configuration file
    generate_config_file(min_lon, max_lon, min_lat, max_lat, canvas_size, json_filename)

    # Save the canvas as PNG
    def save_canvas_as_png():
        canvas_to_image(canvas, png_filename)

    # Add a button to save the canvas as PNG
    save_button = tk.Button(root, text="Save as PNG", command=save_canvas_as_png)
    save_button.pack()

    # The rest of your main function (e.g., event bindings, main loop)
    def on_mouse_wheel(event):
        nonlocal scale, offset_x, offset_y
        factor = 1.1 if event.delta > 0 else 0.9
        scale *= factor
        offset_x = (offset_x - event.x) * factor + event.x
        offset_y = (offset_y - event.y) * factor + event.y
        plot_gps_lines_tk(canvas, gps_lines, canvas_size, scale, offset_x, offset_y)

    canvas.bind("<MouseWheel>", on_mouse_wheel)

    def on_mouse_click(event):
        lon, lat = canvas_to_geo(event.x, event.y, min_lon, max_lon, min_lat, max_lat, canvas_size, scale, offset_x, offset_y)
        print(f"Clicked on: Longitude: {lon:.6f}, Latitude: {lat:.6f}")
        label.config(text=f"Longitude: {lon:.6f}, Latitude: {lat:.6f}")

    canvas.bind("<Button-1>", on_mouse_click)

    label = tk.Label(root, text="Longitude: , Latitude: ", font=("Arial", 12))
    label.pack()

    dragging = False
    drag_start_x = 0
    drag_start_y = 0

    def on_right_button_press(event):
        nonlocal dragging, drag_start_x, drag_start_y
        dragging = True
        drag_start_x = event.x
        drag_start_y = event.y

    def on_right_button_release(event):
        nonlocal dragging
        dragging = False

    def on_mouse_drag(event):
        nonlocal offset_x, offset_y, drag_start_x, drag_start_y
        if dragging:
            dx = event.x - drag_start_x
            dy = event.y - drag_start_y
            offset_x += dx
            offset_y += dy
            drag_start_x = event.x
            drag_start_y = event.y
            plot_gps_lines_tk(canvas, gps_lines, canvas_size, scale, offset_x, offset_y)

    canvas.bind("<Button-3>", on_right_button_press)
    canvas.bind("<ButtonRelease-3>", on_right_button_release)
    canvas.bind("<B3-Motion>", on_mouse_drag)

    root.mainloop()

if __name__ == "__main__":
    main()